package cn.com.anypay.manager.service;

import cn.com.anypay.manager.common.enums.WeChatAuthError;
import cn.com.anypay.manager.common.exception.WeChatAuthException;
import cn.com.anypay.manager.common.utils.WeChatStateUtils;
import cn.com.anypay.manager.dto.config.WeChatAuthConfig;
import cn.com.anypay.manager.dto.wechat.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信API服务类
 * 负责与微信开放平台进行API交互，包括OAuth2.0认证流程
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WeChatService {
    
    private final WeChatAuthConfig weChatAuthConfig;
    private final WeChatApiClient weChatApiClient;
    private final WeChatStateUtils weChatStateUtils;
    
    /**
     * 构建微信OAuth2.0授权URL
     * 
     * @param state 状态参数，用于防止CSRF攻击
     * @return 微信授权URL
     * @throws WeChatAuthException 当配置不完整时抛出异常
     */
    public String buildAuthUrl(String state) {
        log.info("开始构建微信OAuth2.0授权URL, state: {}", state);
        
        try {
            // 验证配置
            if (!weChatAuthConfig.isConfigured()) {
                log.error("微信认证配置不完整");
                throw WeChatAuthException.configError("微信认证配置不完整");
            }
            
            // 验证状态参数
            if (state == null || state.trim().isEmpty()) {
                log.error("状态参数不能为空");
                throw WeChatAuthException.invalidState();
            }
            
            // 构建授权URL
            String encodedRedirectUri = URLEncoder.encode(weChatAuthConfig.getRedirectUri(), StandardCharsets.UTF_8);
            String authUrl = UriComponentsBuilder.fromHttpUrl(weChatAuthConfig.getAuthUrl())
                    .queryParam("appid", weChatAuthConfig.getAppId())
                    .queryParam("redirect_uri", encodedRedirectUri)
                    .queryParam("response_type", "code")
                    .queryParam("scope", weChatAuthConfig.getScope())
                    .queryParam("state", state)
                    .fragment("wechat_redirect")
                    .build()
                    .toUriString();
            
            log.info("微信OAuth2.0授权URL构建成功: {}", authUrl.replaceAll("appid=[^&]*", "appid=***"));
            return authUrl;
            
        } catch (Exception e) {
            log.error("构建微信OAuth2.0授权URL失败", e);
            if (e instanceof WeChatAuthException) {
                throw e;
            }
            throw WeChatAuthException.configError("构建授权URL失败: " + e.getMessage());
        }
    }
    
    /**
     * 使用授权码获取访问令牌
     * 
     * @param code 微信授权码
     * @return 微信访问令牌信息
     * @throws WeChatAuthException 当获取令牌失败时抛出异常
     */
    public WeChatAccessToken getAccessToken(String code) {
        log.info("开始获取微信访问令牌, code: {}", code != null ? code.substring(0, Math.min(code.length(), 10)) + "..." : "null");
        
        try {
            // 验证参数
            if (code == null || code.trim().isEmpty()) {
                log.error("授权码不能为空");
                throw WeChatAuthException.invalidCode();
            }
            
            if (!weChatAuthConfig.isConfigured()) {
                log.error("微信认证配置不完整");
                throw WeChatAuthException.configError("微信认证配置不完整");
            }
            
            // 构建请求URL
            String tokenUrl = UriComponentsBuilder.fromHttpUrl(weChatAuthConfig.getTokenUrl())
                    .queryParam("appid", weChatAuthConfig.getAppId())
                    .queryParam("secret", weChatAuthConfig.getAppSecret())
                    .queryParam("code", code)
                    .queryParam("grant_type", "authorization_code")
                    .build()
                    .toUriString();
            
            log.debug("发送获取访问令牌请求到微信API");
            
            // 使用网络层客户端发送请求
            ResponseEntity<WeChatTokenResponse> response = weChatApiClient.executeGet(tokenUrl, WeChatTokenResponse.class);
            
            WeChatTokenResponse tokenResponse = response.getBody();
            
            // 检查响应是否成功
            if (!tokenResponse.isSuccess()) {
                log.error("获取微信访问令牌失败: {}", tokenResponse.getErrorDescription());
                throw WeChatAuthException.fromWeChatError(
                        String.valueOf(tokenResponse.getErrorCode()), 
                        tokenResponse.getErrorMessage()
                );
            }
            
            // 验证响应数据
            if (tokenResponse.getAccessToken() == null || tokenResponse.getOpenId() == null) {
                log.error("微信API返回的令牌数据不完整");
                throw WeChatAuthException.fromWeChatError("50001", "令牌数据不完整");
            }
            
            WeChatAccessToken accessToken = tokenResponse.toAccessToken();
            
            log.info("成功获取微信访问令牌, openId: {}, expiresIn: {}秒", 
                    accessToken.getOpenId(), accessToken.getExpiresIn());
            
            return accessToken;
            
        } catch (Exception e) {
            log.error("获取微信访问令牌时发生未知错误", e);
            if (e instanceof WeChatAuthException) {
                throw e;
            }
            throw WeChatAuthException.fromWeChatError("50099", "未知错误: " + e.getMessage());
        }
    }
    
    /**
     * 获取微信用户信息
     * 
     * @param accessToken 访问令牌
     * @param openId 用户OpenID
     * @return 微信用户信息
     * @throws WeChatAuthException 当获取用户信息失败时抛出异常
     */
    public WeChatUserInfo getUserInfo(String accessToken, String openId) {
        log.info("开始获取微信用户信息, openId: {}", openId);
        
        try {
            // 验证参数
            if (accessToken == null || accessToken.trim().isEmpty()) {
                log.error("访问令牌不能为空");
                throw WeChatAuthException.accessTokenExpired();
            }
            
            if (openId == null || openId.trim().isEmpty()) {
                log.error("OpenID不能为空");
                throw WeChatAuthException.invalidOpenId();
            }
            
            // 构建请求URL
            String userInfoUrl = UriComponentsBuilder.fromHttpUrl(weChatAuthConfig.getUserInfoUrl())
                    .queryParam("access_token", accessToken)
                    .queryParam("openid", openId)
                    .queryParam("lang", "zh_CN")
                    .build()
                    .toUriString();
            
            log.debug("发送获取用户信息请求到微信API");
            
            // 使用网络层客户端发送请求
            ResponseEntity<WeChatUserInfoResponse> response = weChatApiClient.executeGet(userInfoUrl, WeChatUserInfoResponse.class);
            
            WeChatUserInfoResponse userInfoResponse = response.getBody();
            
            // 检查响应是否成功
            if (!userInfoResponse.isSuccess()) {
                log.error("获取微信用户信息失败: {}", userInfoResponse.getErrorDescription());
                throw WeChatAuthException.fromWeChatError(
                        String.valueOf(userInfoResponse.getErrorCode()), 
                        userInfoResponse.getErrorMessage()
                );
            }
            
            // 验证响应数据
            if (userInfoResponse.getOpenId() == null) {
                log.error("微信API返回的用户信息不完整");
                throw WeChatAuthException.userInfoFailed("用户信息不完整");
            }
            
            WeChatUserInfo userInfo = userInfoResponse.toUserInfo();
            
            log.info("成功获取微信用户信息, openId: {}, nickname: {}", 
                    userInfo.getOpenId(), userInfo.getNickname());
            
            return userInfo;
            
        } catch (Exception e) {
            log.error("获取微信用户信息时发生未知错误", e);
            if (e instanceof WeChatAuthException) {
                throw e;
            }
            throw WeChatAuthException.userInfoFailed("未知错误: " + e.getMessage());
        }
    }
    
    /**
     * 刷新访问令牌
     * 
     * @param refreshToken 刷新令牌
     * @return 新的访问令牌信息
     * @throws WeChatAuthException 当刷新令牌失败时抛出异常
     */
    public WeChatAccessToken refreshToken(String refreshToken) {
        log.info("开始刷新微信访问令牌");
        
        try {
            // 验证参数
            if (refreshToken == null || refreshToken.trim().isEmpty()) {
                log.error("刷新令牌不能为空");
                throw WeChatAuthException.accessTokenExpired();
            }
            
            if (!weChatAuthConfig.isConfigured()) {
                log.error("微信认证配置不完整");
                throw WeChatAuthException.configError("微信认证配置不完整");
            }
            
            // 构建请求URL
            String refreshUrl = UriComponentsBuilder.fromHttpUrl(weChatAuthConfig.getRefreshTokenUrl())
                    .queryParam("appid", weChatAuthConfig.getAppId())
                    .queryParam("grant_type", "refresh_token")
                    .queryParam("refresh_token", refreshToken)
                    .build()
                    .toUriString();
            
            log.debug("发送刷新访问令牌请求到微信API");
            
            // 使用网络层客户端发送请求
            ResponseEntity<WeChatTokenResponse> response = weChatApiClient.executeGet(refreshUrl, WeChatTokenResponse.class);
            
            WeChatTokenResponse tokenResponse = response.getBody();
            
            // 检查响应是否成功
            if (!tokenResponse.isSuccess()) {
                log.error("刷新微信访问令牌失败: {}", tokenResponse.getErrorDescription());
                throw WeChatAuthException.fromWeChatError(
                        String.valueOf(tokenResponse.getErrorCode()), 
                        tokenResponse.getErrorMessage()
                );
            }
            
            // 验证响应数据
            if (tokenResponse.getAccessToken() == null || tokenResponse.getOpenId() == null) {
                log.error("微信API返回的令牌数据不完整");
                throw WeChatAuthException.fromWeChatError("50001", "令牌数据不完整");
            }
            
            WeChatAccessToken accessToken = tokenResponse.toAccessToken();
            
            log.info("成功刷新微信访问令牌, openId: {}, expiresIn: {}秒", 
                    accessToken.getOpenId(), accessToken.getExpiresIn());
            
            return accessToken;
            
        } catch (Exception e) {
            log.error("刷新微信访问令牌时发生未知错误", e);
            if (e instanceof WeChatAuthException) {
                throw e;
            }
            throw WeChatAuthException.fromWeChatError("50099", "未知错误: " + e.getMessage());
        }
    }
    
    /**
     * 验证访问令牌是否有效
     * 
     * @param accessToken 访问令牌
     * @param openId 用户OpenID
     * @return 是否有效
     */
    public boolean validateAccessToken(String accessToken, String openId) {
        log.debug("验证微信访问令牌有效性, openId: {}", openId);
        
        try {
            // 通过获取用户信息来验证令牌有效性
            WeChatUserInfo userInfo = getUserInfo(accessToken, openId);
            return userInfo != null && userInfo.isValid();
        } catch (Exception e) {
            log.warn("访问令牌验证失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 生成状态参数
     * 
     * @return 状态参数
     */
    public String generateState() {
        return weChatStateUtils.generateState();
    }
    
    /**
     * 验证状态参数
     * 
     * @param state 状态参数
     * @return 是否有效
     */
    public boolean validateState(String state) {
        return weChatStateUtils.validateState(state);
    }
    
    /**
     * 检查微信登录状态
     * 
     * @param state 状态参数
     * @return 登录状态信息
     */
    public Map<String, Object> checkLoginStatus(String state) {
        log.debug("检查微信登录状态, state: {}", state);
        
        Map<String, Object> statusInfo = new HashMap<>();
        
        try {
            // 验证状态参数
            if (!validateState(state)) {
                statusInfo.put("status", "expired");
                statusInfo.put("message", "状态参数已过期");
                return statusInfo;
            }
            
            // 检查是否有对应的登录会话
            // 由于微信登录是基于授权码的一次性流程，这里主要是检查状态参数的有效性
            // 实际的登录状态会在用户扫码并授权后通过回调或轮询来更新
            
            // 获取状态参数的详细信息
            Map<String, Object> stateInfo = weChatStateUtils.getStateInfo(state);
            
            if (stateInfo == null) {
                statusInfo.put("status", "expired");
                statusInfo.put("message", "状态信息不存在或已过期");
                return statusInfo;
            }
            
            // 检查状态参数是否过期
            Long createTime = (Long) stateInfo.get("createTime");
            long currentTime = System.currentTimeMillis();
            long expireTime = 10 * 60 * 1000; // 10分钟过期
            
            if (currentTime - createTime > expireTime) {
                statusInfo.put("status", "expired");
                statusInfo.put("message", "二维码已过期");
                return statusInfo;
            }
            
            // 检查是否有登录结果
            String loginResult = (String) stateInfo.get("loginResult");
            if ("success".equals(loginResult)) {
                statusInfo.put("status", "confirmed");
                statusInfo.put("message", "登录成功");
                statusInfo.put("data", stateInfo.get("loginData"));
            } else if ("failed".equals(loginResult)) {
                statusInfo.put("status", "error");
                statusInfo.put("message", stateInfo.get("errorMessage"));
            } else if ("scanned".equals(loginResult)) {
                statusInfo.put("status", "scanned");
                statusInfo.put("message", "已扫码，等待确认");
            } else {
                // 默认等待状态
                statusInfo.put("status", "waiting");
                statusInfo.put("message", "等待扫码");
            }
            
            return statusInfo;
            
        } catch (Exception e) {
            log.error("检查微信登录状态失败", e);
            statusInfo.put("status", "waiting");
            statusInfo.put("message", "检查状态失败");
            return statusInfo;
        }
    }
}